package com.yixueyun.orders.Service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yixueyun.base.exception.YiXueYunPlusException;
import com.yixueyun.base.utils.IdWorkerUtils;
import com.yixueyun.base.utils.QRCodeUtil;
import com.yixueyun.messagesdk.model.po.MqMessage;
import com.yixueyun.messagesdk.service.MqMessageService;
import com.yixueyun.orders.Service.OrderService;
import com.yixueyun.orders.config.AlipayConfig;
import com.yixueyun.orders.config.PayNotifyConfig;
import com.yixueyun.orders.mapper.YxyOrdersGoodsMapper;
import com.yixueyun.orders.mapper.YxyOrdersMapper;
import com.yixueyun.orders.mapper.YxyPayRecordMapper;
import com.yixueyun.orders.model.dto.AddOrderDto;
import com.yixueyun.orders.model.dto.PayRecordDto;
import com.yixueyun.orders.model.dto.PayStatusDto;
import com.yixueyun.orders.model.po.YxyOrders;
import com.yixueyun.orders.model.po.YxyOrdersGoods;
import com.yixueyun.orders.model.po.YxyPayRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageBuilderSupport;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private YxyOrdersMapper ordersMapper;
    @Autowired
    private YxyOrdersGoodsMapper ordersGoodsMapper;
    @Autowired
    private YxyPayRecordMapper payRecordMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private MqMessageService mqMessageService;
    @Value("${pay.qrcodeurl}")
    String qrcodeurl;
    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;

    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;
    @Autowired
    private OrderServiceImpl currentProxy;
    @Override
    @Transactional
    public PayRecordDto createOrder(String userId, AddOrderDto addOrderDto) {
        //插入订单表
        YxyOrders xcOrders = saveYxyOrders(userId, addOrderDto);
        //插入支付记录
        YxyPayRecord payRecord = createPayRecord(xcOrders);
        Long payNo = payRecord.getPayNo();
        //生成二维码
        QRCodeUtil qrCodeUtil = new QRCodeUtil();
        String url = String.format(qrcodeurl,payNo);
        String qrCode = null;
        try {
            qrCode = qrCodeUtil.createQRCode(url, 200, 200);
        } catch (IOException e) {
            YiXueYunPlusException.cast("生成二维码失败");
        }
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord,payRecordDto);
        payRecordDto.setQrcode(qrCode);
        return payRecordDto;
    }
    @Transactional
    public YxyOrders saveYxyOrders(String userId,AddOrderDto addOrderDto){
        //幂等性处理
        YxyOrders order = getOrderByBusinessId(addOrderDto.getOutBusinessId());
        if(order!=null){
            return order;
        }
        order = new YxyOrders();
        //生成订单号
        long orderId = IdWorkerUtils.getInstance().nextId();
        order.setId(orderId);
        order.setTotalPrice(addOrderDto.getTotalPrice());
        order.setCreateDate(LocalDateTime.now());
        order.setStatus("600001");//未支付
        order.setUserId(userId);
        order.setOrderType(addOrderDto.getOrderType());
        order.setOrderName(addOrderDto.getOrderName());
        order.setOrderDetail(addOrderDto.getOrderDetail());
        order.setOrderDescrip(addOrderDto.getOrderDescrip());
        order.setOutBusinessId(addOrderDto.getOutBusinessId());//选课记录id
        int insert = ordersMapper.insert(order);
        if(insert <= 0) {
            YiXueYunPlusException.cast("添加订单失败");
        }
        //插入订单明细
        String orderDetailJson = addOrderDto.getOrderDetail();
        List<YxyOrdersGoods> yxyOrdersGoodsList = JSON.parseArray(orderDetailJson, YxyOrdersGoods.class);
        yxyOrdersGoodsList.forEach(goods->{
            YxyOrdersGoods yxyOrdersGoods = new YxyOrdersGoods();
            BeanUtils.copyProperties(goods, yxyOrdersGoods);
            yxyOrdersGoods.setOrderId(orderId);//订单号
            int insert1 = ordersGoodsMapper.insert(yxyOrdersGoods);
            if (insert1 <= 0) {
                YiXueYunPlusException.cast("插入明细表失败");
            }
        });
        return order;
    }

    //根据业务id查询订单,选课记录表中的主键
    public YxyOrders getOrderByBusinessId(String businessId) {
        YxyOrders orders = ordersMapper.selectOne(new LambdaQueryWrapper<YxyOrders>().eq(YxyOrders::getOutBusinessId, businessId));
        return orders;
    }

    /**
     * 插入支付订单
     * @param orders
     * @return
     */
    public YxyPayRecord createPayRecord(YxyOrders orders){
        if(orders==null){
            YiXueYunPlusException.cast("订单不存在");
        }
        if(orders.getStatus().equals("600002")){
            YiXueYunPlusException.cast("订单已支付");
        }
        YxyPayRecord payRecord = new YxyPayRecord();
        //生成支付交易流水号
        long payNo = IdWorkerUtils.getInstance().nextId();
        payRecord.setPayNo(payNo);
        payRecord.setOrderId(orders.getId());//商品订单号
        payRecord.setOrderName(orders.getOrderName());
        payRecord.setTotalPrice(orders.getTotalPrice());
        payRecord.setCurrency("CNY");
        payRecord.setCreateDate(LocalDateTime.now());
        payRecord.setStatus("601001");//未支付
        payRecord.setUserId(orders.getUserId());
        payRecordMapper.insert(payRecord);
        return payRecord;

    }

    /**
     * 根据订单id查询订单是否存在
     * @param payNo  交易记录号
     * @return
     */
    @Override
    public YxyPayRecord getPayRecordByPayno(String payNo) {
        YxyPayRecord yxyPayRecord = payRecordMapper.selectOne(new LambdaQueryWrapper<YxyPayRecord>().eq(YxyPayRecord::getPayNo, payNo));
        return yxyPayRecord;
    }

    /**
     * 查询支付结果
     */
    @Override
    public PayRecordDto queryPayResult(String payNo) {
        YxyPayRecord payRecord = getPayRecordByPayno(payNo);
        if (payRecord == null) {
            YiXueYunPlusException.cast("请重新点击支付获取二维码");
        }
        //支付状态
        String status = payRecord.getStatus();
        //如果支付成功直接返回
        if ("601002".equals(status)) {
            PayRecordDto payRecordDto = new PayRecordDto();
            BeanUtils.copyProperties(payRecord, payRecordDto);
            return payRecordDto;
        }
        //从支付宝查询支付结果
        PayStatusDto payStatusDto = queryPayResultFromAlipay(payNo);
        //保存支付结果
        currentProxy.saveAliPayStatus( payStatusDto);
        //重新查询支付记录
        payRecord = getPayRecordByPayno(payNo);
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord, payRecordDto);
        return payRecordDto;
    }
    /**
     * 请求支付宝查询支付结果
     * @param payNo 支付交易号
     * @return 支付结果
     */
    public PayStatusDto queryPayResultFromAlipay(String payNo){
//========请求支付宝查询支付结果=============
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE); //获得初始化的AlipayClient
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNo);
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                YiXueYunPlusException.cast("请求支付查询查询失败");
            }
        } catch (AlipayApiException e) {
            log.error("请求支付宝查询支付结果异常:{}", e.toString(), e);
            YiXueYunPlusException.cast("请求支付查询查询失败");
        }

        //获取支付结果
        String resultJson = response.getBody();
        //转map
        Map resultMap = JSON.parseObject(resultJson, Map.class);
        Map alipay_trade_query_response = (Map) resultMap.get("alipay_trade_query_response");
        //支付结果
        String trade_status = (String) alipay_trade_query_response.get("trade_status");
        String total_amount = (String) alipay_trade_query_response.get("total_amount");
        String trade_no = (String) alipay_trade_query_response.get("trade_no");
        //保存支付结果
        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setOut_trade_no(payNo);
        payStatusDto.setTrade_status(trade_status);
        payStatusDto.setApp_id(APP_ID);
        payStatusDto.setTrade_no(trade_no);
        payStatusDto.setTotal_amount(total_amount);
        return payStatusDto;
    }

    /**
     * @description 保存支付宝支付结果
     * @param payStatusDto  支付结果信息
     * @return void
     * @author kklmars
     * @date 2023/10/4 16:52
     */
    @Transactional
    public void saveAliPayStatus(PayStatusDto payStatusDto) {
        //支付流水号
        String payNo = payStatusDto.getOut_trade_no();
        YxyPayRecord payRecordByPayno = getPayRecordByPayno(payNo);
        if (payRecordByPayno == null) {
            YiXueYunPlusException.cast("支付记录找不到");
        }
        //拿到订单id
        Long orderId = payRecordByPayno.getOrderId();
        YxyOrders xcOrders = ordersMapper.selectById(orderId);
        if(xcOrders == null) {
            YiXueYunPlusException.cast("找不到相关的订单");
        }
        String status = payRecordByPayno.getStatus();
        if("601002".equals(status)) {
            return ;
        }
        //如果支付成功
        String tradeStatus = payStatusDto.getTrade_status();
        if(tradeStatus.equals("TRADE_SUCCESS")) {
            //更新支付记录表的状态为成功
            payRecordByPayno.setStatus("601002");
            //支付宝订单号
            payRecordByPayno.setOutPayNo(payStatusDto.getTrade_no());
            //第三方支付编号
            payRecordByPayno.setOutPayChannel("Alipay");
            //支付成功时间
            payRecordByPayno.setPaySuccessTime(LocalDateTime.now());
            payRecordMapper.updateById(payRecordByPayno);
            //更新订单表
            xcOrders.setStatus("600002");
            ordersMapper.updateById(xcOrders);
            //将消息写入数据库
            MqMessage mqMessage = mqMessageService.addMessage("payresult_notify", xcOrders.getOutBusinessId(), xcOrders.getOrderType(), null);
            //发送消息到交换机
            notifyPayResult(mqMessage);
        }
    }

    /**
     * 生产方发送消息
     * @param message
     */
    @Override
    public void notifyPayResult(MqMessage message) {
        //构建消息
        //1.将消息转化为JSON
        String jsonString = JSON.toJSONString(message);
        //2.指定消息编码和持久化
        MessageBuilderSupport<Message> message1 = MessageBuilder.withBody(jsonString.getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        //消息id是自增的，作为全局消息id使用
        Long id = message.getId();
        //使用CorrelationData指定回调函数
        CorrelationData correlationData = new CorrelationData(id.toString());
        correlationData.
                getFuture().addCallback(result->{
                    if(result.isAck()) {
                        //消息发送成功
                        log.debug("发送消息成功：{}",jsonString);
                        //将消息删除
                        mqMessageService.completed(id);
                    } else {
                      //消息发送失败
                        log.debug("发送消息失败：{}",jsonString);
                    }
                },ex->{
                    log.debug("发送消息异常：{}",jsonString);
                });
        //广播
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"",message1,correlationData);
    }
}
